/**
 * Copyright (c) 2019-2021,  陈俊兵 (cjb6b.com@gmail.com)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ktjiaoyu.thread.sync;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 陈俊兵 (cjb6b.com@gmail.com)
 * @version 1.0.0
 * @packageName com.ktjiaoyu.thread.sync
 * @fileName ReentrantLockTest.java
 * @createTime 2023/7/24 21:12
 * @lastModify 2023/7/24 21:12
 */
public class ReentrantLockTest {

    public static void main(String[] args) {
        // 锁对象
        Lock lock = new ReentrantLock(true);
        // 演示公平锁
        // Lock lock = new ReentrantLock(true);
        Thread t1 = new Thread(() -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "拿到了锁！");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "释放了锁！");

                // 演示非公平锁
                for (int i = 0; i < 10; i++) {
                    new Thread(() -> {
                        try {
                            lock.lock();
                            System.out.println(Thread.currentThread().getName() + "拿到了锁！");
                        }finally {
                            lock.unlock();
                        }
                    }, "抢锁线程" + (i + 1)).start();
                }
            }finally {
                // unlock一定要加在finally里面，否则一旦出现异常，则会死锁，其他线程永远无法获得锁。
                lock.unlock();
            }

        });
        t1.start();
        try {
            // 保证t1先拿到锁
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        final List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            final int fi = i;
            Thread now = new Thread(() -> {
                if (fi != 0) {
                    // 循环判断上一个线程是否处于等待状态（ReentrantLock用的是LockSupport.park()实现锁等待）;
                    while (threads.get(fi - 1).getState() != Thread.State.WAITING) {
                        try {
                            Thread.sleep(0);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println(Thread.currentThread().getName() + "准备拿锁！");
                try {
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + "拿到了锁！");
                }finally {
                    lock.unlock();
                }
            }, "线程" + (i + 1));
            now.start();
            threads.add(now);
        }

    }
}
